#include "CDeviceManager.h"

#include <iostream>

#include "CMultipleDatalink.h"
#include "util/config.h"

CDeviceManager &CDeviceManager::Instance()
{
    static CDeviceManager _Instance;
    return _Instance;
}

bool CDeviceManager::LoadZlBaseConfiguration(const std::string &path)
{
    monitor_ = nullptr;
    dcb_list_.clear();

    auto ret = config_.Load(path);
    if (!ret)
    {
        return ret;
    }

    auto devices_ = config_.GetDevice();
    for (const auto &d : devices_)
    {
        switch (d.type)
        {
            case zl::zlbase::EDeviceType_DCB:
            {
                // 创建设备
                zl::zlbase::CDeviceFactory<zl::zlbase::IDoorControlBoard> factory;
                auto device = factory.Concreate(d.uuid.c_str(), d.datalink);
                if (!device)
                {
                    break;
                }

                device->SetNumber(d.number);
                std::cout << "open dcb: " << device->Open() << std::endl;
                dcb_list_.insert(std::make_pair(d.number, device));
                break;
            }
            case zl::zlbase::EDeviceType_MCB:
            {
                // 创建链路
                zl::zlbase::CDatalinkFactory df;
                std::shared_ptr<zl::zlbase::IBaseDatalink> datalink = nullptr;
                if (d.uuid == "4936DB3603F4FD7EE39BAE7E03905E40")
                {
                    auto opt1 = d.datalink;
                    auto sender = df.Concreate(opt1);
                    if (!sender)
                    {
                        std::cerr << "create sender datalink failed: " << opt1.remoteaddr << std::endl;
                        break;
                    }
                    auto opt2 = opt1;
                    opt2.localport = opt1.localport + 1;
                    auto reader = df.Concreate(opt2);
                    if (!reader)
                    {
                        std::cerr << "create reader datalink failed: " << opt1.remoteaddr << std::endl;
                        break;
                    }
                    datalink = std::make_shared<CMultipleDatalink>(sender, reader);
                    if (!datalink)
                    {
                        std::cerr << "create datalink failed" << std::endl;
                        break;
                    }
                }
                else
                {
                    datalink = df.Concreate(d.datalink);
                }
                
                // 创建协议
                zl::zlbase::CProtocolFactory<zl::zlbase::IMonitorControlBoardProtocol> pf;
                auto protocol = pf.Concreate(d.uuid.c_str());
                if (!protocol)
                {
                    std::cerr << "create monitor portocol failed: " << d.uuid << std::endl;
                    break;
                }

                // 创建设备
                zl::zlbase::CDeviceFactory<zl::zlbase::IMonitorControlBoard> factory;
                auto device = factory.Concreate();
                if (!device)
                {
                    std::cerr << "create minitor device failed: " << d.type << std::endl;
                    break;
                }

                device->SetComponent(datalink, protocol);
                std::cout << "open monitor: " << device->Open() << std::endl;
                monitor_ = device;
                break;
            }
            default:
                break;
        }
    }

    return ret;
}

bool CDeviceManager::SaveZlBaseConfiguration(const std::string &path)
{
    return config_.Save(path);
}

int32_t CDeviceManager::GetBoxCount()
{
    auto devices = config_.GetDevice();
    int32_t count = 0;
    for (const auto &d : devices)
    {
        count += d.count;
    }
    return count;
}

std::vector<CZlBaseConfig::ZLBaseDevice> CDeviceManager::GetDevicesConfig()
{
    return config_.GetDevice();
}

std::map<int32_t, std::shared_ptr<zl::zlbase::IDoorControlBoard>> CDeviceManager::GetDoorControlBoardList()
{
    return dcb_list_;
}

std::shared_ptr<zl::zlbase::IMonitorControlBoard> CDeviceManager::GetMonitorControlBoard()
{
    return monitor_;
}

void CDeviceManager::ReleaseAllDevices()
{
    monitor_ = nullptr;
    dcb_list_.clear();
}